﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Xms.Abp;

public class XmsProgram//: StartupBase
{
    public static async Task RunAsync<TStartup, TModule>(string[] args)
        where TStartup : XmsAbpStartup<TModule>
        where TModule : XmsAbpStartupModule
    {
        
        //ConsoleManager.Show();

        var builder = new ConfigurationBuilder();
        if (File.Exists(Path.Combine(AppContext.BaseDirectory, "appsettings.json")))
        {
            builder.AddJsonFile(Path.Combine(AppContext.BaseDirectory, "appsettings.json"), true, true);
            builder.AddJsonFile(Path.Combine(AppContext.BaseDirectory, "appsettings.Development.json"), true, true);
        }
        else if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json")))
        {
            builder.AddJsonFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json"), true, true);
            builder.AddJsonFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.Development.json"), true, true);
        }
        else if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json")))
        {
            builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json"), true, true);
            builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.Development.json"), true, true);
        }
        builder.AddEnvironmentVariables();
        var configuration = builder.Build();

        if (args != null && args.Contains("showfolder"))
        {
            Console.WriteLine("当前运行目录：" + AppContext.BaseDirectory);
        }

        if (!string.IsNullOrWhiteSpace(configuration["App:Urls"]))
        {
            var urls = new[] { "--urls=" + configuration["App:Urls"] };
            if (args == null)
            {
                args = urls;
            }
            else if (args.All(r => !r.StartsWith("--urls=")))
            {
                args = args.Union(urls).ToArray();
            }
        }

        var logOutputTemplate = "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Level:u3}] {RequestId} - {Message:lj}{NewLine}{Exception}";//"[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Application}] [{Level:u3}] {RequestId} - {Message:lj}{NewLine}{Exception}";

        void configure(LoggerConfiguration fileLogger, LogEventLevel level)
        {
            fileLogger.Filter.ByIncludingOnly(r =>
                r.Level == level
                && !(r.Properties != null
                    && r.Properties.ContainsKey("SourceContext")
                    && r.Properties["SourceContext"].ToString().StartsWith("Microsoft.EntityFrameworkCore"))
            ).WriteTo.File($"logs/{level.ToString().ToLower()}/log.txt",
                fileSizeLimitBytes: 50 * 1024 * 1024,
                outputTemplate: logOutputTemplate);
        }

        void configureEFCore(LoggerConfiguration fileLogger)
        {
            fileLogger.Filter.ByIncludingOnly(r =>
                r.Properties != null
                && r.Properties.ContainsKey("SourceContext")
                && r.Properties["SourceContext"].ToString().StartsWith("Microsoft.EntityFrameworkCore")
            ).WriteTo.File($"logs/efcore/log.txt",
                fileSizeLimitBytes: 50 * 1024 * 1024,
                outputTemplate: logOutputTemplate);
        }

        var loggerConfiguration = new LoggerConfiguration();
        var levels = new Dictionary<string, LogLevel>();
        configuration.Bind("Logging:LogLevel", levels);
        LogEventLevel ParseLevel(LogLevel level)
        {
            return level switch
            {
                LogLevel.Trace => LogEventLevel.Verbose,
                LogLevel.Warning => LogEventLevel.Warning,
                LogLevel.Error => LogEventLevel.Error,
                LogLevel.Information => LogEventLevel.Information,
                LogLevel.Critical => LogEventLevel.Fatal,
                LogLevel.Debug => LogEventLevel.Debug,
                _ => LogEventLevel.Warning
            };
        }
        foreach (var level in levels)
        {
            var lvl = ParseLevel(level.Value);
            if (level.Key == "Default")
            {
                loggerConfiguration = loggerConfiguration.MinimumLevel.Is(lvl);
            }
            else
            {
                loggerConfiguration = loggerConfiguration.MinimumLevel.Override(level.Key, lvl);
            }
        }

        Log.Logger = loggerConfiguration.Enrich.FromLogContext()
            .Enrich.WithProperty("AppName", configuration["App:Name"])
            .WriteTo.Logger(fileLogger => configureEFCore(fileLogger))
            .WriteTo.Logger(fileLogger => configure(fileLogger, LogEventLevel.Verbose))
            .WriteTo.Logger(fileLogger => configure(fileLogger, LogEventLevel.Debug))
            .WriteTo.Logger(fileLogger => configure(fileLogger, LogEventLevel.Information))
            .WriteTo.Logger(fileLogger => configure(fileLogger, LogEventLevel.Warning))
            .WriteTo.Logger(fileLogger => configure(fileLogger, LogEventLevel.Error))
            .WriteTo.Logger(fileLogger => configure(fileLogger, LogEventLevel.Fatal))
            .WriteTo.Async(c => c.Console(outputTemplate: logOutputTemplate))
            .CreateLogger();

        await CreateHostBuilder<TStartup, TModule>(args).Build().RunAsync();
    }

    private static IHostBuilder CreateHostBuilder<TStartup, TModule>(string[] args)
        where TStartup : XmsAbpStartup<TModule>
        where TModule : XmsAbpStartupModule
    {
        var builder = Host.CreateDefaultBuilder(args)
            .UseAutofac()
            //.UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .UseSerilog()
            .UseWebHostService<TStartup, TModule>();

        return builder;
    }
}
